home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 1 / PC Actual CD 01.iso / trucos / c / c.cd next >
Encoding:
Text File  |  1995-01-04  |  40.7 KB  |  2,198 lines

  1.  
  2.  
  3.  
  4. LENGUAJE C
  5.  
  6. CONTROL DE DISQUETERAS
  7.  
  8. Para mejorar la presentación de un programa es importante tener un
  9. control total de todos los errores que se puedan presentar. Una buena
  10. fuente de problemas son los accesos a las disqueteras. Por ejemplo,
  11. un problema muy clásico es el intento de acceso a una disquetera sin
  12. disco, pues nos encontramos ante el clásico mensaje de «Anular,
  13. Repetir, Descartar?», algo poco deseable dentro de un programa.
  14. Avisar de todos los problemas que se puedan presentar es una buena
  15. forma de mejorar la calidad de un programa.
  16.  
  17. Mediante la rutina biosdisk podemos saber el estado de la disquetera y
  18. así evitar los errores que acabamos de mencionar. Por ejmplo, antes
  19. de abrir un fichero de un disco, podemos ver si realmente está el
  20. disco en la disquetera, y en caso afirmativo, abrirlo. Para comprobar
  21. el estado podemos utilizar el siguiente código:
  22.  
  23. #include <bios.h>
  24.  
  25. main() {
  26.  
  27. int r, unidad = 0;
  28.  
  29. char b[512];
  30.  
  31. r=biosdisk(4,unidad,0,0,0,1,b);
  32.  
  33. r=biosdisk(4,unidad,0,0,0,1,b);
  34.  
  35. switch(r) {
  36.  
  37.  case 0x02: printf("Disco no formateado");break;
  38.  
  39.  case 0x08:
  40.  
  41.  case 0x09: printf("Fallo en el DMA");break;
  42.  
  43.  case 0x0C: printf("Tipo de disco no encontrado");break;
  44.  
  45.  case 0x10: printf("Error en el CRC");break;
  46.  
  47.  case 0x20: printf("Fallo en la controladora");break;
  48.  
  49.  case 0x40: printf("Fallo de búsqueda");break;
  50.  
  51.  case 0x80: printf("No hay disco en la disquetera");break;
  52.  
  53.  default : printf("Ok");break;
  54.  
  55.  }
  56.  
  57. }
  58.  
  59.  
  60. La variable unidad vale 0 para A: y 1 para B:. Se llama dos veces
  61. seguidas a la función biosdisk, ya que la primera vez devuelve un valor
  62. que indica si se ha encontrado un disco, pero sin ver su estado.
  63.  
  64. Ricard Forner Gili
  65.  
  66. Barcelona
  67.  
  68.  
  69. SUPER PIXEL
  70.  
  71. Este programa (realizado en «Quick C» de Microsoft, aunque fácilmente
  72. implementable en «Turbo C») nos proporciona una nueva rutina para
  73. imprimir un pixel en una VGA 640x480. La nueva rutina está realizada
  74. en ensamblador y proporciona una mayor velocidad que la instrucción
  75. «_setpixel». En este programa podemos comparar las dos instrucciones
  76. para ver la diferencia de velocidad de una a otra.
  77.  
  78. #include <graph.h>
  79.  
  80. void DP(int pagina,int i,int p,int color);
  81.  
  82. main()
  83.  
  84. {
  85.  int x,y;char ca;
  86.  
  87.  _setvideomode(_VRES16COLOR);
  88.  
  89.  _clearscreen(_GCLEARSCREEN);
  90.  
  91.  printf("1.- Impresión en 'C' (setpixel).\n");
  92.  
  93.  printf("2.- Impresión 'ASSEMBLY' (dp).\n");
  94.  
  95.  while (ca!='1' && ca!='2') ca=getch();
  96.  
  97.  for (y=0;y<480;y=y+10)
  98.  
  99.  for (x=0;x<640;x=x+1)
  100.  
  101.  if (ca=='1') {_setcolor(1);_setpixel(x,y);}
  102.  
  103.  else DP(0,x,y,1);
  104.  
  105.  _setvideomode(_DEFAULTMODE);
  106.  
  107. }
  108.  
  109. void DP(int pagina,int t,int p,int color)
  110.  
  111. {
  112.  
  113.  _asm{
  114.  
  115.  mov bh,[bp+6];
  116.  
  117.  mov cx,[bp+8];
  118.  
  119.  mov dx,[bp+10];
  120.  
  121.  mov al,[bp+12];
  122.  
  123.  mov ah,0Ch;
  124.  
  125.  int 10h;
  126.  
  127.  }
  128.  
  129. }
  130.  
  131. Juan Vercher Martínez
  132.  
  133. Gandía (Valencia)
  134.  
  135.  
  136.  
  137. INCLUYA 16 COLORES EN EL FONDO
  138.  
  139. Este programa es un ejempo de cómo utilizar los colores comprendidos
  140. entre el 8 y el 15 como color de fondo. Hemos de recordar que para el
  141. color de fondo sólo podemos utilizar los colores del 0 al 7, de ahí la
  142. motivación de este truco.
  143.  
  144. La rutina «parpadeo()» funciona por medio de la interrupción 10h
  145. subservicio 03h, que permite activar o desactivar el atributo de
  146. parpadeo. La ROM BIOS utiliza el parpadeo por defecto, pero cambiando
  147. el valor del atributo se pueden utilizar los 16 colores para el fondo.
  148. El valor que se pasa en BL determina si el valor está activado (01h) o
  149. desactivado (00h).
  150.  
  151. Es necesario utilizar la función «textattr()» (para definir los dos
  152. colores se puede emplear la fórmula ColorTexto+ColorFondo*16) para
  153. cambiar el color, ya que con las funciones «textcolor()» y
  154. «textbackground()» no es posible, puesto que reestablecen el atributo
  155. para parpadeo.
  156.  
  157. #include <stdio.h>
  158.  
  159. #include <dos.h>
  160.  
  161. #include <conio.h>
  162.  
  163. enum BOOLEAN {OFF, ON};
  164.  
  165. void parpadeo (enum BOOLEAN activar);
  166.  
  167. void parpadeo (enum BOOLEAN activar)
  168.  
  169. {
  170.  
  171.  union REGS regs;
  172.  
  173.  regs.h.bl=activar ? 0x01 : 0x00;
  174.  
  175.  regs.h.ah=0x10;
  176.  
  177.  regs.h.al=0x03;
  178.  
  179.  int86(0x10,®s,®s);
  180.  
  181. }
  182.  
  183. void main()
  184.  
  185. {
  186.  
  187.  int i,j;
  188.  
  189.  enum BOOLEAN parpadear;
  190.  
  191.  textattr( 0 + 15 * 16);
  192.  
  193.  cprintf("\n\rFONDO");
  194.  
  195.  for(i=1;i<16;i++) cprintf(" %2d ",i);
  196.  
  197.  for(i=0;i<16;i++)
  198.  
  199.  for (j=0;j<16;j++)
  200.  
  201.  {
  202.  
  203.  textattr(i+j*16);
  204.  
  205.  cprintf("Texto");
  206.  
  207.  }
  208.  
  209.  textattr(0+15*16);
  210.  
  211.  cprintf("Pulsa Esc para finalizar, otra tecla "
  212.  
  213.  "para cambiar el atributo de parpadeo...");
  214.  
  215.  parpadear = ON;
  216.  
  217.  while(i!=27)
  218.  
  219.  {
  220.  
  221.  parpadear=!parpadear;
  222.  
  223.  parpadeo(parpadear);
  224.  
  225.  i=getch();
  226.  
  227.  }
  228.  
  229.  parpadeo(ON);
  230.  
  231. }
  232.  
  233.  
  234. Antonio Jesús Ollero Sanguino
  235.  
  236. Casar de Cáceres (Cáceres)
  237.  
  238.  
  239.  
  240. TECLADOS VELOCES
  241.  
  242. La ROM-BIOS permite obtener las teclas pulsadas a una velocidad máxima
  243. de 30 caracteres por segundo y con un retardo de autorrepetición de
  244. 0,25 segundos. Algunas veces interesa que el retardo de
  245. autorrepetición sea menor y leer a más velocidad. Esta rutina
  246. soluciona este problema.
  247.  
  248. #include <Dos.h>
  249.  
  250. usigned char obt_tecla (void);
  251.  
  252. {
  253.  
  254.  unsigned int *cabeza=(unsigned int *) (0x0000041a);
  255.  
  256.  unsigned int *cola=(unsigned int *) (0x0000041c);
  257.  
  258.  *cabeza=*cola
  259.  
  260.  return portb(0x60);
  261.  
  262. }
  263.  
  264. El funcionamiento de la rutina está basado en la lectura del código de
  265. letra pulsada directamente del puerto, y además se vacía el buffer del
  266. teclado para que no se llene, ya que no se saca la tecla mediante
  267. ninguna llamada a la ROM-BIOS.
  268.  
  269. Utilidad: Esta función puede ser de gran utilidad para juegos, en los
  270. cuales se requiere mover un gráfico o ejecutar una acción según la
  271. tecla pulsada. En estos casos suele resultar bastante lento tener que
  272. esperar los 0,25 segundos para que el ordenador detecte que se
  273. mantiene pulsada la misma tecla.
  274.  
  275. Jorge Pastor Mondejar
  276.  
  277. Molina de Segura (Murcia)
  278.  
  279.  
  280. SCROLL DE TEXTO
  281.  
  282. Esta rutina realiza un scroll en pantalla mediante el uso de las
  283. interrupciones de la BIOS. La ventaja de esta técnica radica en que
  284. permite la realización un scroll en una ventana.
  285.  
  286. Los parámetros que se le pasan a la rutina son los siguientes:
  287.  
  288. Fijo: atributo; este parámetro representa el color.
  289.  
  290. Fil: fila superior de la ventana donde se realiza el
  291. scroll.
  292.  
  293. Col: columna más a la izquierda de la ventana donde se hace el
  294. scroll.
  295.  
  296. Fils: fila inferior de la ventana donde se realiza el
  297. scroll.
  298.  
  299. Col: columna más a la derecha de la ventana donde se hace el
  300. scroll.
  301.  
  302. Atr: Función a realizar. Dependiendo de los parámetros que le
  303. pasemos aquí podrá realizar «scroles» hacia arriba, abajo, etc, (es
  304. conveniente investigar).
  305.  
  306. Numfils: número de líneas a mover.
  307.  
  308. #include <bios.h>
  309.  
  310. #include <stdio.h>
  311.  
  312. #include <conio.h>
  313.  
  314. union REGS inregs, outregs;
  315.  
  316. void scroll (int fijo, int fil, int col, int fils, int cols, int atr,
  317. int numfils)
  318.  
  319. {
  320.  
  321. inregs.h.ah = atr;
  322.  
  323. inregs.h.al = numfils;
  324.  
  325. inregs.h.bh = fijo;
  326.  
  327. inregs.h.ch = fil;
  328.  
  329. inregs.h.cl = col;
  330.  
  331. inregs.h.dh = fils;
  332.  
  333. inregs.h.dl = cols;
  334.  
  335. int86(0x10, &inregs, &outregs);
  336.  
  337. }
  338.  
  339. /* Programa de ejemplo */
  340.  
  341. main()
  342.  
  343. {
  344.  
  345. int i,u;
  346.  
  347. clrscr();
  348.  
  349. for (i=0; i<30; i++)
  350.  
  351. {
  352.  
  353. gotoxy(50,3);
  354.  
  355. printf("%d",i);
  356.  
  357. scroll(7,2,49,19,60,7,1);
  358.  
  359. getch();
  360.  
  361. }
  362.  
  363. }
  364.  
  365. David G. Peris
  366.  
  367. Barcelona
  368.  
  369.  
  370. SALIR AL DOS
  371.  
  372. El objetivo de esta rutina es el de poder implementar un shell al DOS
  373. en los menús de nuestros propios programas.
  374.  
  375. Para realizar este cometido invocaremos una llamada al «command.com»
  376. mediante la orden «SYSTEM», una vez que sepamos que el interprete de
  377. comandos está en nuestro path activo. Si el «command.com» no se
  378. encuentra en el path activo, sale de la función devolviendo 0, si no
  379. lo ejecuta y cuando se teclea «EXIT» devuelve 1.
  380.  
  381. Para saber si el «command.com» está a nuestra disposición, utilizamos
  382. la sentencia «SEARCHPATH» de la líbreria <dir.h>. Si el «command.com»
  383. está disponible devuelve la ruta completa de acceso a él; en caso
  384. contrario devuelve «NULL».
  385.  
  386. El programa ha sido compilado mediante «Turbo C/C++ 1.0».
  387.  
  388. #include <dir.h>
  389.  
  390. #include <stdlib.h>
  391.  
  392. #include <conio.h>
  393.  
  394. int dos_shell();
  395.  
  396. /* main de ejemplo */
  397.  
  398. main ()
  399.  
  400. {
  401.  
  402.  if dos_shell()==0)
  403.  
  404.  cprintf("\nNo se encontró COMMAND COM en el path activo\n");
  405.  
  406.  return 0;
  407.  
  408. }
  409.  
  410. int dos_shell()
  411.  
  412. {
  413.  
  414. char *camino=NULL;
  415.  
  416. camino =searchpath("COMMAND.COM");
  417.  
  418. if (camino==NULL) return 0;
  419.  
  420. clrscr();
  421.  
  422. cprintf ("Teclea Exit para volver al programa. \n");
  423.  
  424. system (camino);
  425.  
  426. clrscr();
  427.  
  428. return 1;
  429.  
  430. }
  431.  
  432. José Luis Moncada Collado
  433.  
  434. Sant Adriá de Besós (Barcelona)
  435.  
  436.  
  437.  
  438. EFECTO OPTICO
  439.  
  440. Este es un pequeño truco para lograr esos efectos «visuales» que tanto
  441. suelen gustar a la gente. Consiste en un CLS muy llamativo, ya que
  442. todo lo que hay en la pantalla de texto desaparecerá como si de niebla
  443. o humo se tratase. Es ideal para programas en modo texto que no
  444. pueden acceder a los trucos que permite el modo gráfico.
  445.  
  446. El programa accede directamente al buffer de vídeo y ahí va
  447. incrementando en uno todos los caracteres distintos de 0 (para evitar
  448. un bucle infinito) y todos los distintos de « » (para no tocar el
  449. fondo, sólo el texto), así hasta que no quedan más que ceros o « »
  450. (espacio en blanco) entonces ya se habrá borrado la pantalla.
  451. Funciona tanto en color como en monocromo, y está realizado con el
  452. Borland C++ 3.1 en ANSI C. Por lo que debería funcionar sin problemas
  453. en cualquier compilador de C que cumpla la norma ANSI.
  454.  
  455.  #include <stdio.h>;
  456.  
  457.  #include <dos.h>;
  458.  
  459.  #include <stdlib.h>;
  460.  
  461.  int modo_video(void),modov,humo(void);
  462.  
  463.  char far *mem_video;
  464.  
  465.  main()
  466.  
  467.  {
  468.  
  469.  modov=modo_video();
  470.  
  471.  if ((modov!=2) && (modov!=3) && (modov!=7)) {
  472.  
  473.  printf("\nEl modo de video debe estar en 80 columnas.");
  474.  
  475.  exit(1);
  476.  
  477.  }
  478.  
  479.  if (modov==7)
  480.  
  481.  mem_video = (char far *) 0xb0000000; /*Monocromo*/
  482.  
  483.  else
  484.  
  485.  mem_video = (char far *) 0xb8000000; /*Color */
  486.  
  487.  do{
  488.  
  489.  }while (humo()); /*Mientras humo devuelva un 1 es que hay caracteres*/
  490.  
  491.  printf("Prueba de desaparicion de caracteres realizada");
  492.  
  493.  return(0);
  494.  
  495.  }
  496.  
  497. int modo_video(void)
  498.  
  499.  {
  500.  
  501.  union REGS r;
  502.  
  503.  r.h.ah=15; /*obtiene el modo de video */
  504.  
  505.  return int86(0x10,&r,&r) & 255;
  506.  
  507.  }
  508.  
  509. int humo(void)
  510.  
  511.  {
  512.  
  513.  register char far *p;
  514.  
  515.  int bandera=0;
  516.  
  517.  for (p=mem_video;p<mem_video+80*25*2;p++,p++)
  518.  
  519.  if ((*p!=0) && (*p!=32)){
  520.  
  521.  (*p)++;
  522.  
  523.  bandera=1;
  524.  
  525.  }
  526.  
  527.  return(bandera);
  528.  
  529.  }
  530.  
  531. Antonio Javier García Martínez
  532.  
  533. Granada
  534.  
  535.  
  536. GUARDAR Y RESTAURAR PANTALLAS
  537.  
  538. Las siguientes rutinas realizadas en C++ son una mejora de las rutinas
  539. publicadas en el número de febrero para guardar y restaurar pantallas
  540. de texto. Estos procedimientos muestran su utilidad cuando abrimos un
  541. menú, cuadro de diálogo o ventana y al cerrarlo deseamos que
  542. reaparezca el contenido de la pantalla tal y como estaba
  543. anteriormente.
  544.  
  545. La ventajas que ofrecen las nuevas rutinas es que trabajan
  546. directamente con la memoria de vídeo. Para ello se basan en el
  547. principio de que los modos de texto de 80x25 disponen de cuatro
  548. páginas de vídeo que normalmente no se utilizan. Estos nuevos
  549. procedimientos -«SaveScreen (...)» y «RestScreen(...)»- copian las
  550. pantallas a otra página, lo que permite que el acceso sea más rápido.
  551.  
  552. Tan sólo presentan una desventaja producida por la limitación de
  553. páginas de vídeo disponibles, pues en el modo 80x25 sólo disponemos de
  554. tres páginas libres y en el modo 40x25 de siete páginas. En cada
  555. página libre podremos guardar una pantalla.
  556.  
  557. El siguiente programa de ejemplo captura la pantalla de texto, despues
  558. espera a que se pulse una tecla, borra la pantalla y espera de nuevo
  559. otra pulsación de tecla, tras la cual restaura el contenido original
  560. de la pantalla.
  561.  
  562. #include <stdio.h>
  563.  
  564. #include <mem.h>
  565.  
  566. void SaveScreen (unsigned short Pagina);
  567.  
  568. void RestScreen (unsigned short Pagina);
  569.  
  570. void main(void);
  571.  
  572. {
  573.  
  574.  printf ("PC Actual");
  575.  
  576.  int c;
  577.  
  578.  SaveScreen (1);
  579.  
  580.  c=getchar();
  581.  
  582.  clrscr();
  583.  
  584.  c=getchar;
  585.  
  586.  RestScreen(1);
  587.  
  588. }
  589.  
  590.  
  591. // Funciones Principales //
  592.  
  593. void SaveScreen (unsigned short Pagina);
  594.  
  595. {
  596.  unsigned int Pos=Pagina*0x1000;
  597.  
  598.  movedata (0xB800, 0x0000, 0xB800, Pos, 4000);
  599.  
  600. }
  601.  
  602. void RestScreen (unsigned short Pagina);
  603.  
  604. {
  605.  
  606.  unsigned int Pos=Pagina*0x1000;
  607.  
  608.  movedata (0xB800, Pos, 0xB800, 0x0000, 4000);
  609.  
  610. }
  611.  
  612.  
  613. Daniel Sánchez Teodoro
  614.  
  615. Granada
  616.  
  617.  
  618. ESCALA DE GRISES
  619.  
  620. Esta rutina realizada en Turbo C, aunque fácilmente adaptable a Pascal
  621. o ensamblador, transforma la paleta de la pantalla MCGA o VGA 256
  622. colores (320 x 200 con 256 colores) a sus correspondientes valores de
  623. la escala de grises. En definitiva, cuando llamamos a esta función el
  624. gráfico de la pantalla se pone en blanco y negro, tal y como vemos en
  625. muchas máquinas recreativas.
  626.  
  627. Para transformar la paleta de la pantalla a grises ejecutaremos
  628. gris(0), mientras que para devolver a su estado original una paleta
  629. convertida a escala de grises escribiremos gris(1).
  630.  
  631. Las dos rutinas para gris se pueden incluir en el módulo principal del
  632. programa en C, pero en caso de que deseemos linkar esta función como
  633. un módulo separado no hay que olvidar incluir el fichero «.h» para
  634. acceder a ella.
  635.  
  636. /* Función de transformación de grises
  637.  
  638. #include <dos.h>
  639.  
  640. #define GRIS 0
  641.  
  642. #define COLOR 1
  643.  
  644. void gris(void);
  645.  
  646. static unsigned char paleta_antigua[256][3];
  647.  
  648. static unsigned char activado;
  649.  
  650. void gris (char modo)
  651.  
  652. {
  653.  
  654. switch(modo){
  655.  
  656. case COLOR;
  657.  
  658.  if (!activado) break; /*sale si no hay grises */
  659.  
  660.  _ES = FP_SEG(paleta_antigua); /*Estas dos siempre primero */
  661.  
  662.  _DX = FP_OFF(paleta_antigua);
  663.  
  664.  _AX = 0x1012; /* Función BIOS para definir PALETA */
  665.  
  666.  _BX = 0;
  667.  
  668.  _CX = 256;
  669.  
  670.  geninterrupt (0x10); /* Llama a la BIOS */
  671.  
  672.  activado=~activado; /* Muta el indicador */
  673.  
  674.  break;
  675.  
  676. case GRIS;
  677.  
  678.  if (activado) break; /*sale si ya hay grises */
  679.  
  680.  _ES = FP_SEG(paleta_antigua); /*Estas dos siempre primero */
  681.  
  682.  _DX = FP_OFF(paleta_antigua);
  683.  
  684.  _AX = 0x1017; /* Salva la paleta de color antigua */
  685.  
  686.  _BX = 0;
  687.  
  688.  _CX = 256;
  689.  
  690.  geninterrupt (0x10); /* Llama a la BIOS */
  691.  
  692.  _AX = 0x101B; /* Pasa a grises */
  693.  
  694.  _BX = 0;
  695.  
  696.  _CX = 256;
  697.  
  698.  geninterrupt (0x10); /* Llama a la BIOS */
  699.  
  700.  activado=~activado; /* Muta el indicador */
  701.  
  702.  break;
  703.  
  704. }
  705.  
  706. }
  707.  
  708. Fichero «gris.h»:
  709.  
  710. /* Cabecera del módulo transformador de grises vía BIOS (MCGA-VGA) */
  711.  
  712. extern void gris(void);
  713.  
  714. #define GRIS 0
  715.  
  716. #define COLOR 1
  717.  
  718. Luis Díaz Villanueva
  719.  
  720. Madrid
  721.  
  722. Comentario del Laboratorio: La rutina se basa en la utilización de la
  723. interrupción 10 de la BIOS (encargada de los servicios de vídeo),
  724. aunque más en concreto en la función 10, cuya misión es la gestión de
  725. los registros de la paleta de colores. La paleta de colores en el
  726. modo VGA 256 está formada por 256 registros (uno por color) con tres
  727. valores cada uno (para la cantidad de rojo, verde y azul de cada
  728. color)
  729.  
  730. Para llevar a cabo el truco se hace uso de la subfunción 12, cuya
  731. misión es la asignación de un bloque de registros de color; la
  732. subfunción 17, que lee un bloque de registros de color, y, por último,
  733. de la subfunción 1B, que suma los valores de color para pasar a tonos
  734. de grises. Estas funciones necesitan tener cargado en ES la dirección
  735. del segmento donde se encuentra la tabla donde leeremos o grabaremos
  736. los registros de color de la paleta. Además, en DX debe cargarse el
  737. desplazamiento (offset) de dicha tabla.
  738.  
  739. Para efectuar la llamada a la función cargamos el 10 (del número de
  740. función) en el registro AH y el número de subfunción en el registro
  741. AL. Por ejemplo, cuando ejecutamos «gris(0)» en el truco llamamos a
  742. la subfunción 12, por eso en este caso cargamos en AH el 10 y en AL el
  743. 12, lo que es equivalente a cargar 1012 en AX. Una vez que hemos
  744. cargado el valor de la función a emplear debemos pasar en BX el número
  745. de color desde el que queremos empezar a trabajar; en este caso nos
  746. interesa el primer color (el 0) para convertir toda la paleta.
  747. Además, en CX cargaremos el número de colores que queremos convertir.
  748. Por último, modificando los valores de BX y CX conseguiremos tratar
  749. sólo un determinado rango de colores. Tras haber cargado todos los
  750. valores en cada uno de los registros se efectúa la llamada a la
  751. interrupción 10.
  752.  
  753.  
  754. RUTINAS PARA LA PALETA
  755.  
  756. Esta librería para C puede ser de gran utilidad para todos los
  757. programadores que utilicen cualquier modo gráfico y deseen «jugar» con
  758. la paleta de colores.
  759.  
  760. La función «set_rgb» sirve para establecer los valores RGB, es decir,
  761. las cantidades de rojo, verde y azul (en este orden) que forman el
  762. color («col»). La función «get_rgb» efectúa el proceso contrario, es
  763. decir, dado el color «col» nos devuelve la cantidad de rojo, verde y
  764. azul que componen dicho color.
  765.  
  766. También podremos utilizar «Make_gradiente» para crear una escala de
  767. gradientes. Como argumentos se le pasan los valores RGB (rojo, verde
  768. y azul) del color inicial y del color final, así como el color en que
  769. comienza la escala y el número de colores que la compondrán (si este
  770. último argumento es negativo se pueden obtener escalas hacia atras).
  771.  
  772. Por último, la función «ciclo» se utiliza para conseguir que una
  773. sección de la paleta gire o rote sus colores. Se le pasan como
  774. argumentos el color inicial y final del segmento de paleta deseado.
  775. Con este efecto se consigue un resultado especialmente vistoso
  776. utilizándolo en un bucle, logrando un efecto semejante al utilizado en
  777. algunos programas de fractales (como el Fractint).
  778.  
  779. Un ejemplo de esto último es:
  780.  
  781. while (!kbhit())
  782.  
  783. {
  784.  
  785.  ciclo(0,255);
  786.  
  787. }
  788.  
  789.  
  790. La librería es la siguiente:
  791.  
  792. #include <dos.h>
  793.  
  794. typedef unsigned char byte;
  795.  
  796. typedef struct
  797.  
  798. {
  799.  
  800.  byte r;
  801.  
  802.  byte g;
  803.  
  804.  byte b;
  805.  
  806. }rgb;
  807.  
  808. void set_rgb (byte r, byte g, byte b, byte col);
  809.  
  810. rgb get_rgb (byte col);
  811.  
  812. void ciclo (byte inicio, byte fin);
  813.  
  814. void make_gradiente (byte, byte, byte, byte, byte, byte, byte, int );
  815.  
  816. void set_rgb (byte r, byte g, byte b, byte col)
  817.  
  818. {
  819.  
  820.  outportb(0x3c8, col);
  821.  
  822.  outportb(0x3c9, r);
  823.  
  824.  outportb(0x3c9, g);
  825.  
  826.  outportb(0x3c9, b);
  827.  
  828. }
  829.  
  830. rgb get_rgb (byte col)
  831.  
  832. {
  833.  
  834.  rgb result;
  835.  
  836.  outportb(0x3c7, col);
  837.  
  838.  result.r=inport(0x3c9);
  839.  
  840.  result.g=inport(0x3c9);
  841.  
  842.  result.b=inport(0x3c9);
  843.  
  844.  return (result);
  845.  
  846. }
  847.  
  848. void ciclo (byte inicio, byte fi)
  849.  
  850. {
  851.  
  852.  int cont=0;
  853.  
  854.  rgb ci=get_rgb(inicio);
  855.  
  856.  rgb c;
  857.  
  858.  for (cont=inicio; cont <final; cont++)
  859.  
  860.  {
  861.  
  862.  c=get_rgb(cont+1);
  863.  
  864.  set_rgb(c.r, c.g, c.b, cont);
  865.  
  866.  }
  867.  
  868.  set_rgb(ci.r, ci.g, ci.b, final);
  869.  
  870. }
  871.  
  872. void make_gradiente (byte R1, byte G1, byte B1, byte R2,
  873.  
  874.  byte G2, byte B2, byte inicio, int numtonos)
  875.  
  876. {
  877.  
  878.  int deltaR, deltaG, deltaB;
  879.  
  880.  int cont, sent = 1;
  881.  
  882.  int n=abs(numtonos);
  883.  
  884.  byte col=0;
  885.  
  886.  rgb c;
  887.  
  888.  if (n==0) return;
  889.  
  890.  deltaR=R2-R1;
  891.  
  892.  deltaG=G2-G1;
  893.  
  894.  deltaB=B2-B1;
  895.  
  896.  if (numtonos<0) sent=-1;
  897.  
  898.  for (col=ini, cont=0, cont<=n; cont++, col+=sent)
  899.  
  900.  {
  901.  
  902.  c.r =R1+(deltaR*cont/n);
  903.  
  904.  c.g =G1+(deltaR*cont/n);
  905.  
  906.  c.b =B1+(deltaR*cont/n);
  907.  
  908.  set_rgb(c.r, c.g, c.b, col);
  909.  
  910.  }
  911.  
  912. }
  913.  
  914. Fernando Moyano
  915.  
  916. Pamplona
  917.  
  918.  
  919. CAMBIO DE LETRAS
  920.  
  921. Las siguientes rutinas han de ser llamadas desde otra función, y
  922. permiten convertir los caracteres normales en cursivas, negritas y
  923. subrayadas. Es tarea fácil partir de estas rutinas para crear otras
  924. que hagan cualquier otra cosa, y es algo que puede ser útil para
  925. usarlo en algún programa, dándole un toque de distición.
  926.  
  927. #include <dos.h>
  928.  
  929. #include <conio.h>
  930.  
  931. #include <stdio.h>
  932.  
  933. typedef unsigned int word;
  934.  
  935. typedef unsigned char byte;
  936.  
  937. byte far* LoadFont()
  938.  
  939. /*Esta rutina usa las fuentes de 16 bytes*/
  940.  
  941. {
  942.  
  943.  word wSegment,wOffset;
  944.  
  945.  asm{
  946.  
  947.  mov di,bp
  948.  
  949.  mov ah,0x11
  950.  
  951.  mov al,0x30
  952.  
  953.  mov bh,6
  954.  
  955.  int 0x10
  956.  
  957.  push es
  958.  
  959.  push bp
  960.  
  961.  mov bp,di
  962.  
  963.  pop ax
  964.  
  965.  mov wOffset,ax
  966.  
  967.  pop ax
  968.  
  969.  mov wSegment,ax
  970.  
  971.  }
  972.  
  973.  return (byte far*)MK_FP(wSegment,wOffset);
  974.  
  975. }
  976.  
  977. void SetFont(byte far *pby)
  978.  
  979. /*Esta rutina usa las fuentes de 16 bytes*/
  980.  
  981. {
  982.  
  983.  asm{
  984.  
  985.  push bp
  986.  
  987.  mov ah,0x11
  988.  
  989.  mov al,0
  990.  
  991.  mov bh,16 /*16bytes por carácter*/
  992.  
  993.  mov bl,0
  994.  
  995.  mov cx,97 /*97 caracteres*/
  996.  
  997.  mov dl,'!' /*carácter a partir del cual comienzo*/
  998.  
  999.  mov dh,0
  1000.  
  1001.  les bp,pby
  1002.  
  1003.  int 0x10
  1004.  
  1005.  pop bp
  1006.  
  1007.  }
  1008.  
  1009. }
  1010.  
  1011. void Bold()
  1012.  
  1013. /*Esta rutina usa las fuentes de 16 bytes*/
  1014.  
  1015. {
  1016.  
  1017.  byte far *pbyOld,pbyNew[16*97];
  1018.  
  1019.  int i;
  1020.  
  1021.  pbyOld=LoadFont();
  1022.  
  1023.  for(i=0;i<16*97;i++)
  1024.  
  1025.  pbyNew[i]=(pbyOld[i+16*33]>>1)|pbyOld[i+16*33];
  1026.  
  1027.  SetFont(pbyNew);
  1028.  
  1029. }
  1030.  
  1031. void Underlined()
  1032.  
  1033. /*Esta rutina usa las fuentes de 16 bytes*/
  1034.  
  1035. {
  1036.  
  1037.  byte far *pbyOld,pbyNew[16*97];
  1038.  
  1039.  int i;
  1040.  
  1041.  pbyOld=LoadFont();
  1042.  
  1043.  for(i=0;i<16*97;i++)
  1044.  
  1045.  if(i%16==15)
  1046.  
  1047.  pbyNew[i]=0xFF;
  1048.  
  1049.  else
  1050.  
  1051.  pbyNew[i]=pbyOld[i+16*33];
  1052.  
  1053.  
  1054.  SetFont(pbyNew);
  1055.  
  1056. }
  1057.  
  1058. void Cursive()
  1059.  
  1060. /*Esta rutina usa las fuentes de 16 bytes*/
  1061.  
  1062. {
  1063.  
  1064.  byte far *pbyOld,pbyNew[16*97];
  1065.  
  1066.  int i;
  1067.  
  1068.  pbyOld=LoadFont();
  1069.  
  1070.  for(i=0;i<16*97;i++)
  1071.  
  1072.  switch(i%16)
  1073.  
  1074.  {
  1075.  
  1076.  case 2:
  1077.  
  1078.  case 3:
  1079.  
  1080.  pbyNew[i]=pbyOld[i+16*33]>>2;
  1081.  
  1082.  break;
  1083.  
  1084.  case 4:
  1085.  
  1086.  case 5:
  1087.  
  1088.  pbyNew[i]=pbyOld[i+16*33]>>1;
  1089.  
  1090.  break;
  1091.  
  1092.  case 10:
  1093.  
  1094.  case 11:
  1095.  
  1096.  pbyNew[i]=pbyOld[i+16*33]<<1;
  1097.  
  1098.  break;
  1099.  
  1100.  case 12:
  1101.  
  1102.  case 13:
  1103.  
  1104.  pbyNew[i]=pbyOld[i+16*33]<<2;
  1105.  
  1106.  break;
  1107.  
  1108.  default:
  1109.  
  1110.  pbyNew[i]=pbyOld[i+16*33];
  1111.  
  1112.  }
  1113.  
  1114.  SetFont(pbyNew);
  1115.  
  1116. }
  1117.  
  1118. Daniel Pérez Palomar
  1119.  
  1120. Barcelona
  1121.  
  1122.  
  1123.  
  1124. CONTROL DE LA IMPRESORA
  1125.  
  1126. Esta rutina sirve para programas que deseen conocer el estado de la
  1127. impresora antes de mandar algo a imprimir, y en el caso de que no esté
  1128. correctamente conectada puedan mandar el código de error
  1129. correspondiente.
  1130.  
  1131. El programa está realizado en Borland C++ 2.0, y hace uso de la
  1132. función «biosprint» de la librería «bios.h».
  1133.  
  1134. Está función actúa bajo los registros de la BIOS y nos permitirá saber
  1135. si nuestra impresora está ocupada, tiene algún error en el dispositivo
  1136. de entrada/salida, si tiene papel, etc.
  1137.  
  1138. La función «biosprint» trabaja devolviendo un valor que se guardará en
  1139. este caso en la variable «printer». Según el valor que reciba
  1140. sabremos su estado. Otra utilidad de esta función es la de
  1141. reinicializar la impresora una vez ya conectada. Esto puede resultar
  1142. de gran utilidad, si se desean eliminar los datos del buffer de la
  1143. impresora cuando se está realizando un programa. Se hace cambiando el
  1144. valor «estado» por 1, de tal modo que la impresora se reiniciará.
  1145.  
  1146. #include <conio.h>
  1147.  
  1148. #include <bios.h>
  1149.  
  1150. #include <stdio.h>
  1151.  
  1152. #define ESTADO 2
  1153.  
  1154. #define PUERTO 0
  1155.  
  1156. int printer;
  1157.  
  1158. main ()
  1159.  
  1160. {
  1161.  
  1162.  clrscr ();
  1163.  
  1164.  textcolor(cyan + blynk);
  1165.  
  1166.  cprintf ("\n ......... ESTADO DE LA IMPRESORA ..........");
  1167.  
  1168.  printer = biosprint (ESTADO, 0, PUERTO);
  1169.  
  1170.  /* La variable printer almacena el estado de la impresora */
  1171.  
  1172.  if (printer & 0x10) printf ("\n\nImpresora conectada...");
  1173.  
  1174.  
  1175.  else
  1176.  
  1177.  printf("\n\nLa impresora no está conectada...");
  1178.  
  1179.  if (printer & 0x08) printf("\nError en el dispositivo I/O...");
  1180.  
  1181.  else
  1182.  
  1183.  printf("\nNo hay error en el dispositivo I/O...");
  1184.  
  1185.  if (printer & 0x01) printf (\nPaso del tiempo adjudicado...");
  1186.  
  1187.  else
  1188.  
  1189.  printf("\nNO - paso del tiempo adjudicado...");
  1190.  
  1191.  if (printer & 0x20) printf ("\nLa impresora no encuentra el papel...");
  1192.  
  1193.  else
  1194.  
  1195.  printf("\nLa impresora tiene papel...");
  1196.  
  1197.  if (printer & 0x40) printf ("\nSI - Acuse de recibo...");
  1198.  
  1199.  else
  1200.  
  1201.  printf(\nNO - Acuse de recibo...");
  1202.  
  1203.  if (printer & 0x80) printf("\nImpresora no ocupada...");
  1204.  
  1205.  else
  1206.  
  1207.  printf("\nImpresora ocupada...");
  1208.  
  1209.  getch();
  1210.  
  1211.  exit(1);
  1212.  
  1213. }
  1214.  
  1215. Lluís Company Ordoño
  1216.  
  1217. Terrassa (Barcelona)
  1218.  
  1219.  
  1220. ELEGIR EL DIRECTORIO
  1221.  
  1222. Todos nos hemos sentido tentados en alguna ocasión a escribir algún
  1223. pequeño programa que nos facilitase las tareas de movernos por nuestro
  1224. disco duro. Pero el principal inconveniente con el que topábamos era
  1225. que un cambio en el árbol de directorios del mismo nos obligaba a
  1226. reescribir o recompilar la utilidad creada.
  1227.  
  1228. La siguiente rutina nos ofrece una interesante alternativa. En
  1229. efecto, el programa «Eligdir» nos permite situarnos en cualquier
  1230. subdirectorio de la unidad por defecto, con tan sólo algunas
  1231. pulsaciones de teclas de función. Ocupa apenas 11 Kbytes y tan sólo
  1232. lee los 10 primeros subdirectorios de cada nivel (lo que puede ser
  1233. tanto una ventaja como un inconveniente).
  1234.  
  1235. Su algoritmo de funcionamiento es el siguiente. En primer lugar lee
  1236. las entradas en el directorio actual, almacenando en una cola los
  1237. directorios encontrados. A continuación se pide por teclado la
  1238. pulsación de una tecla de función y se salta al directorio asociado a
  1239. la misma leyendo la cola anterior. El proceso se repite hasta que la
  1240. entrada por teclado sea distinta de cualquiera de las teclas de
  1241. función.
  1242.  
  1243. Añadir por último que este programa fue escrito para el compilador
  1244. Turbo C 2.0 de Borland, siendo recomendable su compilación en los
  1245. modelos tiny o small.
  1246.  
  1247. #include <dir.h>
  1248.  
  1249. #include <stdio.h>
  1250.  
  1251. #include <stdlib.h>
  1252.  
  1253. #include <dos.h>
  1254.  
  1255. #include <bios.h>
  1256.  
  1257. char todos[]="*.*";
  1258.  
  1259. /*patrón de búsqueda*/
  1260.  
  1261. struct ffblk f;
  1262.  
  1263. /*file control block*/
  1264.  
  1265. int atributos=FA_DIREC;
  1266.  
  1267. /*atributo de fichero=directorio*/
  1268.  
  1269. int ret;
  1270.  
  1271. /*resultado de funciones findfirst y findnext*/
  1272.  
  1273. char diract[MAXDIR];
  1274.  
  1275. /*cadena con el nombre del camino actual*/
  1276.  
  1277. extern unsigned _stacklen=512;
  1278.  
  1279. /*tamaño de pila y heap (mínimo)*/
  1280.  
  1281. extern unsigned _heaplen=1024;
  1282.  
  1283. struct cola
  1284.  
  1285. /*cola de los directorios seleccionados*/
  1286.  
  1287. {char nombre[13];
  1288.  
  1289.  struct cola *sig;
  1290.  
  1291. } *pcab,*pcola;
  1292.  
  1293. /*punteros a cabeza y fin de la cola*/
  1294.  
  1295. void IniciaC()
  1296.  
  1297. /*Inicia la cola, borrándola*/
  1298.  
  1299. { struct cola *p1,*p2;
  1300.  
  1301.  if (pcab!=NULL)
  1302.  
  1303.  {p1=pcab;p2=pcab->sig;
  1304.  
  1305.  while(p2!=NULL)
  1306.  
  1307.  {free(p1);
  1308.  
  1309.  p1=p2;
  1310.  
  1311.  p2=p2->sig;
  1312.  
  1313.  }
  1314.  
  1315.  free(p1);
  1316.  
  1317.  pcab=NULL;
  1318.  
  1319.  }
  1320.  
  1321. }
  1322.  
  1323. void MeterC(cad)
  1324.  
  1325. /*Mete un string en la cola*/
  1326.  
  1327. char cad[13];
  1328.  
  1329. {struct cola *p2;
  1330.  
  1331.  if ((p2=malloc(sizeof(*p2)))==NULL)
  1332.  
  1333.  {puts("No hay memoria suficiente");exit(0);}
  1334.  
  1335.  strcpy(p2->nombre,cad);
  1336.  
  1337.  p2->sig=NULL;
  1338.  
  1339.  if (pcab==NULL) pcab=p2;
  1340.  
  1341.  else pcola->sig=p2;
  1342.  
  1343.  pcola=p2;
  1344.  
  1345. }
  1346.  
  1347. EsvaciaC()
  1348.  
  1349. /*Comprueba si la cola está vacía*/
  1350.  
  1351. {return(pcab==NULL);}
  1352.  
  1353. void BuscaDIR()
  1354.  
  1355. /*Busca los directorios y los mete en la cola*/
  1356.  
  1357. {short c=0;
  1358.  
  1359.  IniciaC();
  1360.  
  1361.  ret=findfirst(todos,&f,atributos);
  1362.  
  1363.  /*busca el primero*/
  1364.  
  1365.  if (ret==-1) return;
  1366.  
  1367.  /*si no está, salir*/
  1368.  
  1369.  if (f.ff_attrib==FA_DIREC && (f.ff_name[0]!='.'))
  1370.  
  1371.  /*si es directorio válido*/
  1372.  
  1373.  {MeterC(f.ff_name);c++;}
  1374.  
  1375.  /*meterlo en cola*/
  1376.  
  1377.  for(;;)
  1378.  
  1379.  {ret=findnext(&f);
  1380.  
  1381.  /*busca el siguiente*/
  1382.  
  1383.  if ((ret==-1) || (c>10)) break;
  1384.  
  1385.  /*si no encontrado o hay más de 10, salir*/
  1386.  
  1387.  if (f.ff_attrib==FA_DIREC) {MeterC(f.ff_name);c++;}
  1388.  
  1389.  }
  1390.  
  1391. if (EsvaciaC()) {puts("No encontré directorios");exit(0);}
  1392.  
  1393. }
  1394.  
  1395. void Eligeopcion()
  1396.  
  1397. /*Muestra los directorios seleccionados y pide uno de ellos*/
  1398.  
  1399. {struct cola *p;
  1400.  
  1401.  int c,d;
  1402.  
  1403.  int tecla;
  1404.  
  1405.  getcurdir(0,diract);
  1406.  
  1407.  /*escribe directorio actual*/
  1408.  
  1409.  printf ("\n\n DIRECTORIO ACTUAL : \\%s",diract);
  1410.  
  1411.  puts ("\n Elige directorio: ");
  1412.  
  1413.  for(p=pcab,c=1;p!=NULL && c<=10;p=p->sig,c++)
  1414.  
  1415.  printf ("\n F%d - %s",c,p->nombre);
  1416.  
  1417.  puts ("\n OTRA CUALQUIERA - fin");
  1418.  
  1419.  tecla=bioskey(0)>>8;
  1420.  
  1421.  /*obtiene código tecla pulsada*/
  1422.  
  1423.  if ((tecla<0x3b)||(tecla>0x44)) exit(0);
  1424.  
  1425.  /*si no es tecla función, salir*/
  1426.  
  1427.  tecla-=0x3b;
  1428.  
  1429.  for(p=pcab,d=0;(tecla>d) && (p!=NULL);p=p->sig,d++);
  1430.  
  1431.  /*ir a dir seleccionado*/
  1432.  
  1433.  chdir(p->nombre);
  1434.  
  1435. }
  1436.  
  1437. main() /*Rutina principal*/
  1438.  
  1439. {BuscaDIR();
  1440.  
  1441.  while(!EsvaciaC())
  1442.  
  1443.  {Eligeopcion();
  1444.  
  1445.  BuscaDIR();
  1446.  
  1447.  }
  1448.  
  1449. }
  1450.  
  1451. Gonzalo León Manzano
  1452.  
  1453. Albacete
  1454.  
  1455.  
  1456. EFECTO DE SOMBREADO
  1457.  
  1458. Con esta función en C podemos dotar a nuestros programas de ventanas y
  1459. menús con sombra. Las cajas son sencillas de hacer con las funciones
  1460. y procedimientos incluidos en C, pero la dificultad surge al crear las
  1461. sombras. Esta función nos ayudará durante el proceso de sombreado.
  1462.  
  1463. El truco está en leer los caracteres adecuados de la pantalla y
  1464. cambiarles el atributo que llevan asociado, es decir, el color de
  1465. primer plano y el de fondo. El nuevo atributo ha de ser gris sobre
  1466. negro.
  1467.  
  1468. La siguiente función se usa para crear el efecto descrito alrededor de
  1469. una región rectangular de coordenadas (x1,y1) (x2,y2).
  1470.  
  1471. // Esta función dibuja una "sombra" en función de las coordenadas
  1472. dadas
  1473.  
  1474. // Se supone que se habrá dibujado una caja con esas mismas
  1475. coordenadas
  1476.  
  1477. // Para hacer la sombra se cambia el atributo de los caracteres
  1478. adecuados
  1479.  
  1480. // a gris sobre negro
  1481.  
  1482. void Shadow(int x1,int y1,int x2,int y2)
  1483.  
  1484. {
  1485.  
  1486.  int j=0;
  1487.  
  1488.  char ch;
  1489.  
  1490.  union REGS r;
  1491.  
  1492.  // Se dibuja el lado inferior de la sombra
  1493.  
  1494.  for(j=x1+2;j<x2+3;j++)
  1495.  
  1496.  {
  1497.  
  1498.  gotoxy(j,y2+1); // coloco el cursor en la posición adecuada
  1499.  
  1500.  r.h.ah=0x08;
  1501.  
  1502.  r.h.bh=0x00;
  1503.  
  1504.  int86(0x10,&r,&r); // consigo el carácter de esa posición
  1505.  
  1506.  ch=r.h.al; // ch contiene el carácter
  1507.  
  1508.  textattr(7); // cambio el atributo del carácter
  1509.  
  1510.  putch(ch); // y lo pongo de nuevo
  1511.  
  1512.  }
  1513.  
  1514.  //-- se dibuja el lado derecho de la sombra --
  1515.  
  1516.  for(j=y1+1;j<y2+1;j++)
  1517.  
  1518.  {
  1519.  
  1520.  gotoxy(x2+1,j); // coloco el cursor en la posición adecuada
  1521.  
  1522.  r.h.ah=0x08;
  1523.  
  1524.  r.h.bh=0x00;
  1525.  
  1526.  int86(0x10,&r,&r); // consigo el carácter de esa posición
  1527.  
  1528.  ch=r.h.al; // ch contiene el carácter
  1529.  
  1530.  textattr(7); // cambio el atributo del carácter
  1531.  
  1532.  putch(ch); // y lo pongo de nuevo
  1533.  
  1534.  }
  1535.  
  1536.  for(j=y1+1;j<y2+1;j++)
  1537.  
  1538.  {
  1539.  
  1540.  gotoxy(x2+2,j); // coloco el cursor en posición
  1541.  
  1542.  r.h.ah=0x08;
  1543.  
  1544.  r.h.bh=0x00;
  1545.  
  1546.  int86(0x10,&r,&r); // consigo el carácter adecuado
  1547.  
  1548.  ch=r.h.al; // ch contiene el carácter
  1549.  
  1550.  textattr(7); // cambio el atributo del carácter
  1551.  
  1552.  putch(ch); // y lo vuelvo a colocar en su sitio
  1553.  
  1554.  }
  1555.  
  1556. }
  1557.  
  1558. Daniel Sánchez Teodoro
  1559.  
  1560. Granada
  1561.  
  1562.  
  1563. DESARROLLA TUS PROPIOS ESTEREOGRAMAS
  1564.  
  1565. Con esta rutina podemos realizar estereogramas de una sola imagen.
  1566. Los estereogramas son esas extrañas imágenes (tan de moda hoy en día)
  1567. que «esconden» objetos en tres dimensiones, pero que pueden verse
  1568. empleando una determinada técnica. Demetrio Fernández nos ha mandado
  1569. una rutina creada por él mismo que permite, a partir de una imagen,
  1570. desarrollar un estereograma. Está escrita en C y sorprende por su
  1571. pequeño tamaño, pues tan sólo ocupa menos de 60 líneas.
  1572.  
  1573. Para sacar provecho de todas sus prestaciones basta con crear el
  1574. dibujo o imagen, ponerla en pantalla y luego llamar al procedimiento
  1575. «pantalla».
  1576.  
  1577. unsigned rep=40;
  1578.  
  1579. // ancho de repetición
  1580.  
  1581. unsigned aleatorio[200];
  1582.  
  1583. // patrón con el que trabaja el programa
  1584.  
  1585. unsigned aleatorio2[200];
  1586.  
  1587. // patrón original
  1588.  
  1589. unsigned maximo=40;
  1590.  
  1591. //igual que rep pero este es temporal
  1592.  
  1593. unsigned NPUNTOS=1;
  1594.  
  1595. //el número de puntos que se saltan
  1596.  
  1597. unsigned paralelo=1;
  1598.  
  1599. // modo de visualización en paralelo o cruzado
  1600.  
  1601. // hace un simple negativo de la imagen
  1602.  
  1603. void genera(unsigned ini,unsigned fin)
  1604.  
  1605. // cuando hay que aumentar el aleatorio
  1606.  
  1607. // mete trozos del aleatorio2
  1608.  
  1609. {
  1610.  
  1611.  int i,j,d;
  1612.  
  1613.  d=fin-ini;
  1614.  
  1615.  j=random(rep-d);
  1616.  
  1617.  for(i=ini;i<fin;i++)
  1618.  
  1619.  {aleatorio[i]=aleatorio2[j+i-ini];}
  1620.  
  1621. }
  1622.  
  1623. void genera2(unsigned *tabl,unsigned ini,unsigned fin)
  1624.  
  1625. // aquí genera puntos aleatorios pero
  1626.  
  1627. // podéis poner lo que queráis como patron
  1628.  
  1629. {
  1630.  
  1631.  int i;
  1632.  
  1633.  for(i=ini;i<fin;i++)
  1634.  
  1635.  {tabl[i]=random(getmaxcolor());}
  1636.  
  1637. }
  1638.  
  1639. void adelante(unsigned ini,unsigned salto)
  1640.  
  1641. // incrementamos profundidad en la imagen
  1642.  
  1643.  
  1644. {
  1645.  
  1646.  unsigned i;
  1647.  
  1648.  for (i=maximo;i>ini;i--) aleatorio[i+NPUNTOS*salto]=aleatorio[i];
  1649.  
  1650.  maximo+=NPUNTOS*salto;
  1651.  
  1652.  genera(i,i+NPUNTOS*salto);
  1653.  
  1654. }
  1655.  
  1656. void atras(unsigned ini,unsigned salto)
  1657.  
  1658. // decrementamos profundidad en la imagen
  1659.  
  1660. {
  1661.  
  1662.  unsigned i;
  1663.  
  1664.  for (i=ini;i<maximo;i++) aleatorio[i]=aleatorio[i+NPUNTOS*salto];
  1665.  
  1666.  maximo-=NPUNTOS*salto;
  1667.  
  1668. }
  1669.  
  1670. void rastrealinea(unsigned numlin)
  1671.  
  1672. // genera cada línea
  1673.  
  1674. {
  1675.  
  1676.  unsigned i,j,k;
  1677.  
  1678.  unsigned color;
  1679.  
  1680.  color=0;
  1681.  
  1682.  maximo=rep;
  1683.  
  1684.  genera2(aleatorio,numlin,0,maximo*2);
  1685.  
  1686.  genera2(aleatorio2,numlin,0,maximo*2);
  1687.  
  1688.  j=0;
  1689.  
  1690.  for(i=0;i<getmaxx();i++)
  1691.  
  1692.  {if (paralelo) k=15-getpixel(i,numlin);
  1693.  
  1694.  else k=getpixel(i,numlin);
  1695.  
  1696.  if (k!=color)
  1697.  
  1698.  {if (k<color) adelante(j,color-k);
  1699.  
  1700.  else atras(j,k-color);
  1701.  
  1702.  color=k;}
  1703.  
  1704.  putpixel(i,numlin,aleatorio[j]);
  1705.  
  1706.  j=(j+1)%maximo;}
  1707.  
  1708. }
  1709.  
  1710. void pantalla(void)
  1711.  
  1712. // hace un estereograma de toda la pantalla
  1713.  
  1714. {
  1715.  
  1716. unsigned i;
  1717.  
  1718. for (i=0;i<=getmaxy();i++)
  1719.  
  1720. {
  1721.  
  1722.  if (i%2) rastrealinea(i);
  1723.  
  1724.  else rastrealinea(480-i);}
  1725.  
  1726. }
  1727.  
  1728. Nota sobre la visualización: Christopher W. Tyler fue el creador de
  1729. los estereogramas de una sola imagen. Este tipo de estereogramas no
  1730. son en verdad una sola imagen, sino siete u ocho imágenes iguales
  1731. puestas unas juntas con las otras hasta formar una única imagen y el
  1732. efecto de profundidad. La técnica de visualización consiste en poner
  1733. el punto focal detras de la página que estamos viendo, tratando de
  1734. situar la vista más allá de la hoja. Se consigue acercando la imagen
  1735. (en este caso la pantalla) a los ojos y después separándola (en este
  1736. caso la cabeza) hasta que veamos las tres dimensiones.
  1737.  
  1738. Demetrio Fernández Alvarez
  1739.  
  1740. Oviedo
  1741.  
  1742.  
  1743. TRATAMIENTO DE IMAGENES
  1744.  
  1745. Las siguientes rutinas son dos procedimientos que nos van a permitir,
  1746. en primer lugar, capturar cualquier imagen que se pueda sacar por
  1747. pantalla (incluso aquellas de 256 colores), para convertirla en un
  1748. formato reconocible por la segunda rutina, que será la que dibujará
  1749. esa misma imagen pero adaptándola a un polígono que le pasaremos como
  1750. parámetro.
  1751.  
  1752. Para utilizar estas rutinas en los nuevos programas hay que incluir el
  1753. fichero «trans_ima.h», además de indicar a nuestro compilador que debe
  1754. enlazar nuestro programa y el fichero «trans_ima.c».
  1755.  
  1756. El programa «Trans_ima.h» es el siguiente:
  1757.  
  1758. /* TRANSFORMA IMAGEN
  1759.  
  1760. Este conjunto de rutinas está pensado para capturar imágenes y luego
  1761. adaptarlas a cualquier polígono, sea o no rectangular.
  1762.  
  1763. - captura: Coge una zona de la pantalla gráfica y la captura en el
  1764. formato t_imagen.
  1765.  
  1766. - D_dibuja: Adapta la imagen que se le pasa como parámetro al
  1767. polígono que le indicamos en la variable de tipo t_puntos.
  1768.  
  1769. El tipo t_puntos no es más que un registro con cuatro puntos que
  1770. señalan los vértices de un polígono.
  1771.  
  1772. */
  1773.  
  1774.  struct t_imagen
  1775.  
  1776.  {unsigned tam_max_x,tam_max_y;
  1777.  
  1778.  unsigned char huge *ptr;
  1779.  
  1780.  };
  1781.  
  1782.  struct t_punto
  1783.  
  1784.  {int x,y;};
  1785.  
  1786.  struct t_puntos
  1787.  
  1788.  {struct t_punto p1,p2,p3,p4;};
  1789.  
  1790.  void D_dibuja (struct t_imagen,struct t_puntos);
  1791.  
  1792.  struct t_imagen captura (int,int,int,int);
  1793.  
  1794.  
  1795. El programa «Trans_ima.c» es el siguiente:
  1796.  
  1797.  #include "alloc.h"
  1798.  
  1799.  #include "graphics.h"
  1800.  
  1801.  #include "math.h"
  1802.  
  1803.  #include "trans_ima.h"
  1804.  
  1805.  struct t_coef
  1806.  
  1807.  {float x,y;};
  1808.  
  1809.  struct t_coefs
  1810.  
  1811.  {struct t_coef c1,c2,c3,c4;};
  1812.  
  1813.  void calcula_coef (struct t_puntos,struct t_coefs *);
  1814.  
  1815.  void calcula_incremento_a (struct t_puntos,float *);
  1816.  
  1817.  void calcula_incremento_b (struct t_puntos puntos,float *incb);
  1818.  
  1819.  struct t_punto S_destino (float,float,struct t_coefs);
  1820.  
  1821.  struct t_punto S_origen (struct t_imagen,float,float);
  1822.  
  1823.  int color_origen (struct t_imagen,struct t_punto);
  1824.  
  1825.  struct t_imagen captura (int x1,int y1,int x2,int y2)
  1826.  
  1827.  {unsigned i,j;
  1828.  
  1829.  struct t_imagen imagen;
  1830.  
  1831.  unsigned seg;
  1832.  
  1833.  int error;
  1834.  
  1835.  imagen.ptr = farmalloc ((unsigned long) (y2-y1+1)*(x2-x1+1));
  1836.  
  1837.  if (imagen.ptr != NULL)
  1838.  
  1839.  {imagen.tam_max_x = x2-x1;
  1840.  
  1841.  imagen.tam_max_y = y2-y1;
  1842.  
  1843.  for (i=0;i<=y2-y1;i++)
  1844.  
  1845.  {for (j=0;j<=x2-x1;j++)
  1846.  
  1847.  {imagen.ptr [(unsigned long) i*(x2-x1+1)+j] = getpixel (x1+j,y1+i);}
  1848.  
  1849.  }
  1850.  
  1851.  }
  1852.  
  1853.  return (imagen);
  1854.  
  1855.  }
  1856.  
  1857.  void calcula_coef (struct t_puntos puntos,struct t_coefs *coef)
  1858.  
  1859.  {
  1860.  
  1861.  coef->c1.x = puntos.p1.x-puntos.p2.x+puntos.p3.x-puntos.p4.x;
  1862.  
  1863.  coef->c1.y = puntos.p1.y-puntos.p2.y+puntos.p3.y-puntos.p4.y;
  1864.  
  1865.  coef->c2.x = puntos.p4.x-puntos.p3.x;
  1866.  
  1867.  coef->c2.y = puntos.p4.y-puntos.p3.y;
  1868.  
  1869.  coef->c3.x = puntos.p2.x-puntos.p3.x;
  1870.  
  1871.  coef->c3.y = puntos.p2.y-puntos.p3.y;
  1872.  
  1873.  coef->c4.x = puntos.p3.x;
  1874.  
  1875.  coef->c4.y = puntos.p3.y;
  1876.  
  1877.  }
  1878.  
  1879.  struct t_punto S_destino (float alfa,float beta,struct t_coefs coef)
  1880.  
  1881.  {struct t_punto p;
  1882.  
  1883.  p.x = (int) (alfa*beta*coef.c1.x + alfa*coef.c2.x + beta*coef.c3.x +
  1884.  coef.c4.x);
  1885.  
  1886.  p.y = (int) (alfa*beta*coef.c1.y + alfa*coef.c2.y + beta*coef.c3.y +
  1887.  coef.c4.y);
  1888.  
  1889.  return (p);
  1890.  
  1891.  }
  1892.  
  1893.  struct t_punto S_origen (struct t_imagen imagen,float alfa,float beta)
  1894.  
  1895.  {struct t_punto p;
  1896.  
  1897.  p.x = imagen.tam_max_x -(int) (beta*imagen.tam_max_x);
  1898.  
  1899.  p.y = imagen.tam_max_y -(int) (alfa*imagen.tam_max_y);
  1900.  
  1901.  return (p);
  1902.  
  1903.  }
  1904.  
  1905.  int color_origen (struct t_imagen imagen,
  1906.  
  1907.  struct t_punto p)
  1908.  
  1909.  {
  1910.  
  1911.  return (imagen.ptr [(unsigned long) p.y*(imagen.tam_max_x+1)+p.x]);
  1912.  
  1913.  }
  1914.  
  1915.  void calcula_incremento_a (struct t_puntos puntos,float *inca)
  1916.  
  1917.  {unsigned dist1,dist2;
  1918.  
  1919.  float dist;
  1920.  
  1921.  int vx,vy;
  1922.  
  1923.  vx = abs (puntos.p2.x-puntos.p1.x);
  1924.  
  1925.  vy = abs (puntos.p2.y-puntos.p1.y);
  1926.  
  1927.  dist1 = ((vx > vy) ? vx : vy);
  1928.  
  1929.  vx = abs (puntos.p3.x-puntos.p4.x);
  1930.  
  1931.  vy = abs (puntos.p3.y-puntos.p4.y);
  1932.  
  1933.  dist2 = ((vx > vy) ? vx : vy);
  1934.  
  1935.  dist = (((dist1) > (dist2)) ? (dist1) : (dist2));
  1936.  
  1937.  *inca = 1/(dist+1);
  1938.  
  1939.  }
  1940.  
  1941.  void calcula_incremento_b (struct t_puntos puntos,float *incb)
  1942.  
  1943.  {unsigned dist1,dist2;
  1944.  
  1945.  float dist;
  1946.  
  1947.  int vx,vy;
  1948.  
  1949.  vx = abs (puntos.p4.x-puntos.p1.x);
  1950.  
  1951.  vy = abs (puntos.p4.y-puntos.p1.y);
  1952.  
  1953.  dist1 = ((vx > vy) ? vx : vy);
  1954.  
  1955.  vx = abs (puntos.p2.x-puntos.p3.x);
  1956.  
  1957.  vy = abs (puntos.p2.y-puntos.p3.y);
  1958.  
  1959.  dist2 = ((vx > vy) ? vx : vy);
  1960.  
  1961.  dist = (((dist1) > (dist2)) ? (dist1) : (dist2));
  1962.  
  1963.  *incb = 1/(dist+1);
  1964.  
  1965.  }
  1966.  
  1967.  void D_dibuja (struct t_imagen origen,
  1968.  
  1969.  struct t_puntos puntos)
  1970.  
  1971.  {float alfa,beta;
  1972.  
  1973.  struct t_punto p;
  1974.  
  1975.  struct t_coefs coef;
  1976.  
  1977.  int color;
  1978.  
  1979.  float inca,incb;
  1980.  
  1981.  calcula_incremento_a (puntos,&inca);
  1982.  
  1983.  calcula_incremento_b (puntos,&incb);
  1984.  
  1985.  calcula_coef (puntos,&coef);
  1986.  
  1987.  for (alfa=0;alfa<=1;alfa+=inca)
  1988.  
  1989.  for (beta=0;beta<=1;beta+=incb)
  1990.  
  1991.  {p = S_origen (origen,alfa,beta);
  1992.  
  1993.  color = color_origen (origen,p);
  1994.  
  1995.  p = S_destino (alfa,beta,coef);
  1996.  
  1997.  putpixel (p.x,p.y,color);
  1998.  
  1999.  }
  2000.  
  2001.  }
  2002.  
  2003. Siguiendo estos pasos, tenemos a nuestra disposición dos rutinas:
  2004.  
  2005. - struct t_imagen captura(int x1, int y1, int x2, int y2)
  2006.  
  2007. - void D_dibuja (struct t_imagen imagen, struct t_puntos p)
  2008.  
  2009. La primera función captura el mapa de bits comprendido entre los
  2010. puntos (x1,y1) y (x2,y2), devolviendo un registro de tipo t_imagen, en
  2011. el que queda almacenada.
  2012.  
  2013. El segundo procedimiento coge la imagen previamente capturada y la
  2014. dibuja adaptándola al polígono de cuatro vértices indicado por la
  2015. variable p.
  2016.  
  2017. Hemos de tener en cuenta que la imagen capturada se almacena en
  2018. memoria principal como una matriz de char, con un byte por cada
  2019. pixel que capturemos. Por lo que si los bitmaps van a ser muy
  2020. grandes tendremos que compilar el programa en modelos como «Compact».
  2021.  
  2022. En el siguiente programa vemos un ejemplo de la utilización de estas
  2023. rutinas:
  2024.  
  2025.  #include "alloc.h"
  2026.  
  2027.  #include "graphics.h"
  2028.  
  2029.  #include "stdio.h"
  2030.  
  2031.  #include "fcntl.h"
  2032.  
  2033.  #include "io.h"
  2034.  
  2035.  #include "trans_ima.h"
  2036.  
  2037.  struct t_imagen carga_origen (char *);
  2038.  
  2039.  int inicia_graficos ();
  2040.  
  2041.  int main ()
  2042.  
  2043.  {struct t_puntos puntos;
  2044.  
  2045.  struct t_imagen origen;
  2046.  
  2047.  char *cadena = "PC-ACTUAL";
  2048.  
  2049.  char *aux = " \0";
  2050.  
  2051.  int i;
  2052.  
  2053.  inicia_graficos ();
  2054.  
  2055.  /* PRIMERO SIMPLEMENTE DIBUJAMOS UNA IMAGEN EN LA PANTALLA */
  2056.  
  2057.  settextstyle (DEFAULT_FONT,HORIZ_DIR,3);
  2058.  
  2059.  moveto (0,0);
  2060.  
  2061.  for (i=0;i < strlen (cadena);i++)
  2062.  
  2063.  {setcolor (i+1);
  2064.  
  2065.  strnset (aux,cadena [i],1);
  2066.  
  2067.  outtext (aux);
  2068.  
  2069.  }
  2070.  
  2071.  setcolor (i+1);
  2072.  
  2073.  line (0,textheight (cadena),textwidth (cadena),textheight (cadena));
  2074.  
  2075.  /* CAPTURAMOS LA PARTE DE LA PANTALLA QUE NOS INTERESA EN UNA VARIABLE
  2076.  DE TIPO ORIGEN */
  2077.  
  2078.  origen.tam_max_x = textwidth (cadena);
  2079.  
  2080.  origen.tam_max_y = textheight (cadena);
  2081.  
  2082.  origen = captura (0,0,origen.tam_max_x,origen.tam_max_y);
  2083.  
  2084.  settextstyle (DEFAULT_FONT,HORIZ_DIR,1);
  2085.  
  2086.  setcolor (WHITE);
  2087.  
  2088.  outtextxy (0,getmaxy ()-textheight ("P"),
  2089.  
  2090.  "Pulsa una tecla para ver la imagen transformada...");
  2091.  
  2092.  getch ();
  2093.  
  2094.  if (origen.ptr != NULL) /* ¿HA HABIDO ERROR EN ASIGNACION DE MEMORIA? */
  2095.  
  2096.  {cleardevice ();
  2097.  
  2098.  /* DIBUJAMOS LA IMAGEN TRANSFORMADA */
  2099.  
  2100.  puntos.p1.x = 0;puntos.p1.y = 0;
  2101.  
  2102.  puntos.p2.x = 0;puntos.p2.y = getmaxy ();
  2103.  
  2104.  puntos.p3.x = getmaxx ()/2-50;puntos.p3.y = getmaxy ()/2+40;
  2105.  
  2106.  puntos.p4.x = getmaxx ()/2-50;puntos.p4.y = getmaxy ()/2-40;
  2107.  
  2108.  D_dibuja (origen,puntos);
  2109.  
  2110.  puntos.p1.x = getmaxx ()/2-40;puntos.p1.y = getmaxy ()/2+50;
  2111.  
  2112.  puntos.p2.x = 0;puntos.p2.y = getmaxy ();
  2113.  
  2114.  puntos.p3.x = getmaxx ();puntos.p3.y = getmaxy ();
  2115.  
  2116.  puntos.p4.x = getmaxx () /2+40;puntos.p4.y = getmaxy ()/2+50;
  2117.  
  2118.  D_dibuja (origen,puntos);
  2119.  
  2120.  puntos.p3.x = getmaxx ()/2+50;puntos.p3.y = getmaxy ()/2+40;
  2121.  
  2122.  puntos.p2.x = getmaxx ();puntos.p2.y = getmaxy ();
  2123.  
  2124.  puntos.p1.x = getmaxx ();puntos.p1.y = 0;
  2125.  
  2126.  puntos.p4.x = getmaxx ()/2+50;puntos.p4.y = getmaxy ()/2-40;
  2127.  
  2128.  D_dibuja (origen,puntos);
  2129.  
  2130.  puntos.p2.x = 0;puntos.p2.y = 0;
  2131.  
  2132.  puntos.p1.x = getmaxx ()/2-40;puntos.p1.y = getmaxy ()/2-50;
  2133.  
  2134.  puntos.p4.x = getmaxx ()/2+40;puntos.p4.y = getmaxy ()/2-50;
  2135.  
  2136.  puntos.p3.x = getmaxx ();puntos.p3.y = 0;
  2137.  
  2138.  D_dibuja (origen,puntos);
  2139.  
  2140.  free ((void *) origen.ptr);
  2141.  
  2142.  getch ();
  2143.  
  2144.  }
  2145.  
  2146.  else {closegraph ();
  2147.  
  2148.  printf ("\nError en asignacion de memoria\n");
  2149.  
  2150.  exit (1);
  2151.  
  2152.  }
  2153.  
  2154.  closegraph ();
  2155.  
  2156.  return (0);
  2157.  
  2158.  }
  2159.  
  2160.  int inicia_graficos ()
  2161.  
  2162.  {int driver,modo,errorcode;
  2163.  
  2164.  driver = DETECT;
  2165.  
  2166.  initgraph (&driver,&modo,"");
  2167.  
  2168.  errorcode = graphresult();
  2169.  
  2170.  if (errorcode != grOk)
  2171.  
  2172.  {
  2173.  
  2174.  printf("Error en graficos: %s\n", grapherrormsg(errorcode));
  2175.  
  2176.  printf("Pulsa una tecla para terminar.");
  2177.  
  2178.  getch();
  2179.  
  2180.  exit(1);
  2181.  
  2182.  }
  2183.  
  2184.  return (graphresult ());
  2185.  
  2186.  }
  2187.  
  2188.  
  2189. Marcial Martínez López
  2190.  
  2191. Valencia
  2192.  
  2193.  
  2194.  
  2195.  
  2196.  
  2197.  
  2198.